package com.xjk.data;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;
import java.util.Objects;
import java.util.Random;

/**
 * @author xjk
 * @date 2024-10-16
 */
public class RandomValue {

  private static final Random RANDOM = new Random();

  /**
   * 生成一个 min 到 max之间的随机BigDecimal
   */
  public static BigDecimal randomBigDecimal(String min, String max,int decimalPlaces) {
    Objects.requireNonNull(min, "min 不能为 null");
    Objects.requireNonNull(max, "max 不能为 null");
    if (decimalPlaces < 0) {
      throw new IllegalArgumentException("decimalPlaces 不能为负数");
    }

    BigDecimal minBd = new BigDecimal(min).setScale(decimalPlaces, RoundingMode.HALF_UP);
    BigDecimal maxBd = new BigDecimal(max).setScale(decimalPlaces, RoundingMode.HALF_UP);

    // 确保 min <= max，如果不满足，则交换
    if (minBd.compareTo(maxBd) > 0) {
      BigDecimal temp = minBd;
      minBd = maxBd;
      maxBd = temp;
    }

    // 缩放因子：10^decimalPlaces
    BigDecimal scaleFactor = BigDecimal.TEN.pow(decimalPlaces);

    // 将 min 和 max 缩放为整数
    BigInteger minScaled = minBd.multiply(scaleFactor).toBigIntegerExact();
    BigInteger maxScaled = maxBd.multiply(scaleFactor).toBigIntegerExact();

    // 计算范围（包含最大值）
    BigInteger range = maxScaled.subtract(minScaled).add(BigInteger.ONE);

    // 生成一个在 [0, range) 之间的随机整数
    BigInteger randomOffset = randomBigInteger(range);

    // 计算最终的随机整数值
    BigInteger randomScaled = minScaled.add(randomOffset);

    // 转换回 BigDecimal 并设置小数位数
    BigDecimal randomValue = new BigDecimal(randomScaled).divide(scaleFactor, decimalPlaces, RoundingMode.HALF_UP);

    return randomValue;
  }
  /**
   * 生成一个介于 0（含）和 upperBound（不含）之间的随机 BigInteger。
   *
   * @param upperBound 上界，必须为正数
   * @return 一个随机的 BigInteger，范围在 [0, upperBound)
   */
  private static BigInteger randomBigInteger(BigInteger upperBound) {
    if (upperBound.compareTo(BigInteger.ONE) <= 0) {
      return BigInteger.ZERO;
    }

    int nBits = upperBound.bitLength();
    BigInteger result;
    do {
      result = new BigInteger(nBits, RANDOM);
    } while (result.compareTo(upperBound) >= 0);
    return result;
  }
}
